package cn.tedu.mall.product.service;

import cn.tedu.mall.common.exception.CoolSharkServiceException;
import cn.tedu.mall.common.restful.JsonPage;
import cn.tedu.mall.common.restful.ResponseCode;
import cn.tedu.mall.pojo.product.dto.BrandAddNewDTO;
import cn.tedu.mall.pojo.product.dto.BrandUpdateDTO;
import cn.tedu.mall.pojo.product.model.Brand;
import cn.tedu.mall.pojo.product.vo.BrandStandardVO;
import cn.tedu.mall.product.constant.CommonConst;
import cn.tedu.mall.product.mapper.BrandCategoryMapper;
import cn.tedu.mall.product.mapper.BrandMapper;
import cn.tedu.mall.product.mapper.SpuMapper;
import cn.tedu.mall.product.redis.constant.RedisConst;
import cn.tedu.mall.product.redis.repo.IBrandRedisRepository;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.Serializable;
import java.util.List;

import static cn.tedu.mall.product.redis.constant.RedisConst.REBUILD_INTERVAL_IN_MINUTE;

/**
 * <p>品牌业务实现类/p>
 *
 * @author tedu.cn
 * @since 2021-11-30
 */
@Service
@Slf4j
public class BrandServiceImpl implements IBrandService {

    @Autowired
    private BrandMapper brandMapper;
    @Autowired
    private BrandCategoryMapper brandCategoryMapper;
    @Autowired
    private SpuMapper spuMapper;
    @Autowired
    private IBrandRedisRepository brandRedisRepository;

    @Override
    public Long addNew(BrandAddNewDTO brandAddNewDTO) {
        // 检查品牌名称是否存在
        String brandName = brandAddNewDTO.getName();
        BrandStandardVO checkNameQueryResult = brandMapper.getByName(brandName);
        if (checkNameQueryResult != null) {
            throw new CoolSharkServiceException(ResponseCode.CONFLICT, "新增品牌失败，品牌名称(" + brandName + ")已存在！");
        }

        // 执行新增
        Brand brand = new Brand();
        BeanUtils.copyProperties(brandAddNewDTO, brand);
        brand.setSort(brandAddNewDTO.getSort() == null ? CommonConst.SORT_DEFAULT : brandAddNewDTO.getSort());
        log.debug("新增品牌:" + brand);
        int rows = brandMapper.insert(brand);
        if (rows != 1) {
            throw new CoolSharkServiceException(ResponseCode.INTERNAL_SERVER_ERROR, "新增品牌失败，服务器忙，请稍后再次尝试！");
        }

        // 返回品牌id
        return brand.getId();
    }

    @Override
    public void deleteById(Long id) {
        // 检查尝试删除的品牌是否存在
        BrandStandardVO currentBrand = brandMapper.getById(id);
        if (currentBrand == null) {
            throw new CoolSharkServiceException(ResponseCode.NOT_FOUND, "删除品牌失败，尝试访问的数据不存在！");
        }

        // 查询品牌与类别的绑定
        {
            int count = brandCategoryMapper.countByBrandId(id);
            if (count > 0) {
                throw new CoolSharkServiceException(ResponseCode.CONFLICT, "删除品牌失败，当前品牌存在与类别的绑定！");
            }
        }

        // 查询关联spu
        {
            int count = spuMapper.countByBrandId(id);
            if (count > 0) {
                throw new CoolSharkServiceException(ResponseCode.CONFLICT, "删除品牌失败，当前品牌存在关联的SPU数据！");
            }
        }

        // 执行删除
        int rows = brandMapper.deleteById(id);
        if (rows != 1) {
            throw new CoolSharkServiceException(ResponseCode.INTERNAL_SERVER_ERROR, "删除品牌失败，服务器忙，请稍后再次尝试！");
        }
    }

    @Override
    public void setEnableById(Long id) {
        // 检查尝试编辑的品牌是否存在
        BrandStandardVO currentBrand = brandMapper.getById(id);
        if (currentBrand == null) {
            throw new CoolSharkServiceException(ResponseCode.NOT_FOUND, "启用品牌失败，尝试访问的数据不存在！");
        }

        // 检查当前状态值
        if (currentBrand.getEnable().equals(1)) {
            throw new CoolSharkServiceException(ResponseCode.CONFLICT, "启用品牌失败，品牌当前已经启用！");
        }

        // 执行更新
        int rows = brandMapper.updateEnableById(id, 1);
        if (rows != 1) {
            throw new CoolSharkServiceException(ResponseCode.INTERNAL_SERVER_ERROR, "启用品牌失败，服务器忙，请稍后再次尝试！");
        }
    }

    @Override
    public void setDisableById(Long id) {
        // 检查尝试编辑的品牌是否存在
        BrandStandardVO currentBrand = brandMapper.getById(id);
        if (currentBrand == null) {
            throw new CoolSharkServiceException(ResponseCode.NOT_FOUND, "禁用品牌失败，尝试访问的数据不存在！");
        }

        // 检查当前状态值
        if (currentBrand.getEnable().equals(1)) {
            throw new CoolSharkServiceException(ResponseCode.CONFLICT, "禁用品牌失败，品牌当前已经启用！");
        }

        // 执行更新
        int rows = brandMapper.updateEnableById(id, 0);
        if (rows != 1) {
            throw new CoolSharkServiceException(ResponseCode.INTERNAL_SERVER_ERROR, "禁用品牌失败，服务器忙，请稍后再次尝试！");
        }
    }

    @Override
    public void updateFullInfoById(Long id, BrandUpdateDTO brandUpdateDTO) {
        // 检查尝试更新的品牌是否存在
        BrandStandardVO currentBrand = brandMapper.getById(id);
        if (currentBrand == null) {
            throw new CoolSharkServiceException(ResponseCode.NOT_FOUND, "更新品牌失败，尝试访问的数据不存在！");
        }

        // 检查新名称是否冲突
        BrandStandardVO checkNameQueryResult = brandMapper.getByName(brandUpdateDTO.getName());
        if (checkNameQueryResult != null && !checkNameQueryResult.getId().equals(id)) {
            throw new CoolSharkServiceException(ResponseCode.CONFLICT, "更新品牌基本信息失败，类别名称(" + checkNameQueryResult.getName() + ")已存在！");
        }

        // 执行更新
        Brand brand = new Brand();
        brand.setId(id);
        BeanUtils.copyProperties(brandUpdateDTO, brand);
        log.debug("更新品牌:" + brand);
        int rows = brandMapper.updateFullInfoById(brand);
        if (rows != 1) {
            throw new CoolSharkServiceException(ResponseCode.INTERNAL_SERVER_ERROR, "更新品牌失败，服务器忙，请稍后再次尝试！");
        }
    }

    @Override
    public BrandStandardVO getById(Long id) {
        // 尝试从Redis中获取数据
        Serializable redisData = brandRedisRepository.getValue(id);
        // 检查Redis中的数据是否存在
        if (redisData == null) {
            // Redis中没有与此id匹配的数据，尝试从数据库中获取数据
            BrandStandardVO brandStandardVO = brandMapper.getById(id);
            // 判断从数据库中是否获取到数据
            if (brandStandardVO == null) {
                // 数据库中仍无此数据，为避免缓存穿透，在Redis中增加空数据
                brandRedisRepository.setEmptyValue(id);
                // 返回错误
                throw new CoolSharkServiceException(ResponseCode.NOT_FOUND, "获取品牌详情失败，尝试访问的数据不存在！");
            } else {
                // 数据库中有此数据，则写入缓存
                brandRedisRepository.setValue(brandStandardVO);
                // 返回有效数据
                return brandStandardVO;
            }
        }
        // 检查Redis中的数据是否为空数据
        if (RedisConst.EMPTY_VALUE.equals(redisData.toString())) {
            // 返回错误
            throw new CoolSharkServiceException(ResponseCode.NOT_FOUND, "获取品牌详情失败，尝试访问的数据不存在！");
        }
        // 返回有效值
        return (BrandStandardVO) redisData;
    }

    @Override
    public JsonPage<BrandStandardVO> list(Integer page, Integer pageSize) {
        List<BrandStandardVO> brands = brandRedisRepository.list(page, pageSize);
        Long total = brandRedisRepository.listSize();
        Integer totalPage = total % page == 0 ? (int) (total / page) : (int) (total / page + 1);
        return JsonPage.restPage(brands, page, pageSize, totalPage, total);
    }

    @Override
    public List<BrandStandardVO> listByCategoryId(Long categoryId) {
        return brandRedisRepository.listByCategory(categoryId);
    }

    @Override
    public void initCache() {
        loadCache();
    }

    @Override
    public void rebuildCache() {
        // 日志
        log.debug("准备重建品牌数据缓存……");
        // 获取最近加载（全部）缓存时间
        Long recentlyLoadTime = brandRedisRepository.getRecentlyLoadTime();
        // 判断记录的时间是否存在
        if (recentlyLoadTime != null) {
            // 判断间隔时间
            long currentTime = System.currentTimeMillis();
            log.debug("最近加载（全部）缓存时间为{}，当前时间为{}，时间差为{}", recentlyLoadTime, currentTime, (currentTime - recentlyLoadTime));
            // 判断是否允许重建品牌数据缓存
            if ((currentTime - recentlyLoadTime) < REBUILD_INTERVAL_IN_MINUTE * 60 * 1000) {
                throw new CoolSharkServiceException(ResponseCode.NOT_ACCEPTABLE,
                        "重建缓存失败，间隔时间必须大于" + REBUILD_INTERVAL_IN_MINUTE + "分钟！");
            }
        }
        // 执行重建品牌数据缓存
        loadCache();
    }

    /**
     * 加载品牌的全部缓存数据
     */
    private void loadCache() {
        // 日志
        log.debug("即将向Redis中写入品牌数据缓存……");
        // 清空原有缓存（仅作用于当前类型数据）
        log.debug("清空Redis中原有品牌数据缓存……");
        brandRedisRepository.flushAll();
        log.debug("已经清空Redis中原有品牌数据缓存。");

        {
            // 加载数据库中的数据
            List<BrandStandardVO> brands = brandMapper.list();
            // 遍历查询结果
            log.debug("向Redis中写入各个品牌数据……");
            for (BrandStandardVO brandStandardVO : brands) {
                // 逐一写入到Redis
                brandRedisRepository.setValue(brandStandardVO);
            }

            // 将整个列表写入到Redis
            log.debug("向Redis中写入品牌列表……");
            brandRedisRepository.appendList(brands);
        }

        // 获取与品牌有关联的类别列表
        List<Long> categoryIdList = brandCategoryMapper.listCategoryIds();
        // 遍历类别id，存入对应的品牌列表
        log.debug("向Redis中写入各类别对应的品牌列表……");
        for (Long categoryId : categoryIdList) {
            List<BrandStandardVO> brands = brandMapper.listByCategoryId(categoryId);
            brandRedisRepository.setListForCategory(categoryId, brands);
        }

        // 记录此次加载缓存的时间
        brandRedisRepository.setRecentlyLoadTime();

        // 日志
        log.debug("向Redis中写入品牌数据缓存，完成！");
    }

}
